// Copyright 2022 a.o.smith ALL Rights Reserved
package com.liuxinlong.modules.chimi.service.impl;

import com.liuxinlong.common.AosException;
import com.liuxinlong.common.SnowFlake;
import com.liuxinlong.enums.BarPointSourceEnum;
import com.liuxinlong.enums.ReturnCodes;
import com.liuxinlong.modules.chimi.service.BarPointsFlowService;
import com.liuxinlong.modules.dao.BarPointsDao;
import com.liuxinlong.modules.dao.BarPointsFlowDao;
import com.liuxinlong.modules.dao.UserDao;
import com.liuxinlong.modules.entity.BarPoints;
import com.liuxinlong.modules.entity.BarPointsFlow;
import com.liuxinlong.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 论坛积分流水服务层接口实现
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2023-02-13
 */
@Service
@Slf4j
public class BarPointsFlowServiceImpl implements BarPointsFlowService {

    @Autowired
    private BarPointsFlowDao barPointsFlowDao;

    @Autowired
    private BarPointsDao barPointsDao;

    @Autowired
    private UserDao userDao;

    @Override
    public List<Map<String, Object>> pagePointsFlow(Map<String, Object> queryParam) {
        int startNum = (int) queryParam.get("startNum");
        List<BarPointsFlow> originalList = barPointsFlowDao.pageBarPointsFlow(queryParam);
        return completeResult(originalList, startNum);
    }

    @Override
    public int getPointsFlowCount(Map<String, Object> queryParam) {
        return barPointsFlowDao.getBarPointsFlowCount(queryParam);
    }

    @Override
    public void addPointsFlow(BarPointsFlow barPointsFlow) {
        barPointsFlow.setId(SnowFlake.nextIdStr());
        barPointsFlowDao.insert(barPointsFlow);
        int currentNum;
        if (barPointsFlow.getType() == 1) {
            currentNum = barPointsFlow.getPoints();
        } else {
            currentNum = -barPointsFlow.getPoints();
        }
        BarPoints bp = barPointsDao.selectById(barPointsFlow.getUserId());
        if (ObjectUtils.isEmpty(bp)) {
            BarPoints barPoints = new BarPoints();
            barPoints.setId(barPointsFlow.getUserId());
            barPoints.setPoints(currentNum);
            barPoints.setStockPoints(currentNum);
            barPointsDao.insert(barPoints);
            return;
        }
        bp.setPoints(bp.getPoints() + currentNum);
        bp.setStockPoints(bp.getStockPoints() + currentNum);
        barPointsDao.updateById(bp);
    }

    @Override
    public void updatePointsFlow(BarPointsFlow barPointsFlow) {
        String id = barPointsFlow.getId();
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分配置信息异常，配置不存在！");
        }
        BarPointsFlow oldInfo = barPointsFlowDao.selectById(id);
        if (ObjectUtils.isEmpty(oldInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改积分配置信息异常，配置不存在！");
        }
        barPointsFlowDao.updateById(barPointsFlow);
    }

    @Override
    public void deletePointsFlow(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "删除积分配置信息异常，配置不存在！");
        }
        BarPointsFlow oldInfo = barPointsFlowDao.selectById(id);
        if (ObjectUtils.isEmpty(oldInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "删除积分配置信息异常，配置不存在！");
        }
        barPointsFlowDao.deleteById(id);
    }

    @Override
    public int checkUserPoints() {
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 10000);
        List<BarPointsFlow> barPointsFlowList = barPointsFlowDao.pageBarPointsFlow(queryParam);
        Map<String, Integer> userPointsMap = new HashMap<>();
        Map<String, Integer> userStockPointsMap = new HashMap<>();
        Set<String> userSet = new HashSet<>();
        int checkNum;
        for (BarPointsFlow barPointsFlow : barPointsFlowList) {
            String userId = barPointsFlow.getUserId();
            int num = userPointsMap.containsKey(userId) ? userPointsMap.get(userId) : 0;
            int stockNum = userStockPointsMap.containsKey(userId) ? userStockPointsMap.get(userId) : 0;
            int targetNum;
            int targetStockNum;
            if (barPointsFlow.getType() == 1) {
                targetNum = num + barPointsFlow.getPoints();
                targetStockNum = stockNum + barPointsFlow.getPoints();
            } else {
                targetNum = num - barPointsFlow.getPoints();
                targetStockNum = stockNum;
            }
            userPointsMap.put(userId, targetNum);
            userStockPointsMap.put(userId, targetStockNum);
            userSet.add(userId);
        }
        List<BarPoints> barPointsList = barPointsDao.getAllUserPoints();
        List<BarPoints> updateList = new ArrayList<>();
        for (BarPoints barPoints : barPointsList) {
            userSet.remove(barPoints.getId());
            if (userPointsMap.containsKey(barPoints.getId())
                    && barPoints.getPoints() == userPointsMap.get(barPoints.getId())
                    && barPoints.getStockPoints() == userStockPointsMap.get(barPoints.getId())) {
                continue;
            }
            if (!userPointsMap.containsKey(barPoints.getId())) {
                updateList.add(barPoints);
                continue;
            }
            barPoints.setPoints(userPointsMap.get(barPoints.getId()));
            barPoints.setStockPoints(userStockPointsMap.get(barPoints.getId()));
            updateList.add(barPoints);
        }
        if (!ObjectUtils.isEmpty(updateList)) {
            barPointsDao.updateBatchById(updateList);
        }
        checkNum = updateList.size();
        if (!ObjectUtils.isEmpty(userSet)) {
            List<BarPoints> addList = new ArrayList<>();
            for (String userId : userSet) {
                BarPoints barPoints = new BarPoints();
                barPoints.setId(userId);
                barPoints.setPoints(userPointsMap.get(userId));
                barPoints.setStockPoints(userStockPointsMap.get(userId));
                addList.add(barPoints);
            }
            checkNum = checkNum + addList.size();
        }
        return checkNum;
    }

    @Override
    public void updateBatchPointsFlow(int sourceType, int targetPoints, String startTime, String endTime) {
        barPointsFlowDao.updateBatchPointsFlow(sourceType, targetPoints, startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> pagePointsRanking(Map<String, Object> queryParam) {
        List<BarPoints> originalList = barPointsDao.pagePointsRanking(queryParam);
        List<Map<String, Object>> resultList = new ArrayList<>(originalList.size());
        Map<String, Map<String, String>> userMap = userDao.getUserMap();
        int sort = (int) queryParam.get("startNum") + 1;
        for (BarPoints barPoints : originalList) {
            Map<String, Object> item = ObjectUtils.object2Map(barPoints);
            item.put("sort", sort);
            item.put("userName", userMap.containsKey(barPoints.getId()) ? userMap.get(barPoints.getId()).get("name") : "");
            resultList.add(item);
            sort++;
        }
        return resultList;
    }

    @Override
    public int getPointsRankingCount(Map<String, Object> queryParam) {
        return barPointsDao.getPointsRankingCount(queryParam);
    }

    @Override
    public void updatePointsRanking(String id) {
        BarPoints pointsInfo = barPointsDao.selectById(id);
        if (ObjectUtils.isEmpty(pointsInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR,"修改失败，用户积分信息不存在!");
        }
        pointsInfo.setStatus(pointsInfo.getStatus() == 0 ? 1 : 0);
        barPointsDao.updateById(pointsInfo);
    }


    /**
     * 数据补全转换
     *
     * @param originList 原始数据列表
     * @param startNum   起始查询数
     * @return 补全数据
     */
    private List<Map<String, Object>> completeResult(List<BarPointsFlow> originList, int startNum) {
        if (ObjectUtils.isEmpty(originList)) {
            return new ArrayList<>();
        }
        Map<String, Map<String, String>> userMap = userDao.getUserMap();
        List<Map<String, Object>> resultList = new ArrayList<>(originList.size());
        int sort = startNum + 1;
        for (BarPointsFlow record : originList) {
            Map<String, Object> map = ObjectUtils.object2Map(record);
            map.put("sort", sort);
            map.put("sourceTypeName", BarPointSourceEnum.getNameByValue(record.getSourceType()));
            map.put("userName", userMap.containsKey(record.getUserId()) ? userMap.get(record.getUserId()).get("name") : "-");
            resultList.add(map);
            sort++;
        }
        return resultList;
    }
}
